#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <json-c/json.h>

typedef struct {
    unsigned int *mic_ip;
    unsigned short *mic_port;
    char *mic_flag;
} MICARRAY;

typedef struct {
    int start;
    int end;
    int ca2;
} STARTENDCA;

#define VERSION 51735
#define CONFIG_FILE "/etc/gzrl.json"
#define RECV_PORT 8888
#define NANO_SECONDS 1000000000
#define TIMEOUT 3000  //ms
#define VOLUME_LEN 800  //m
#define LOG_SOURCE_PORT 6666
#define CHANNEL_NUM 4 //4 channels
#define EXCEPT_LEN 40 //m
#define BEGIN_LEN 80 //m
#define EXCEPT_MAX_RATIO 20 //去掉最大的百分之几
#define AVGNUM 50 //agc时均值个数，200->4hz,88->10hz, 44->20hz
#define PI 3.14
#define BASE 32768
extern char *readConf(char *filename, char *item, char *key, char *ostr);

int write_register(unsigned long offset, int value);
int read_register(unsigned long offset, int *value);
void *init_gxdma(int bsize);
void free_gxdma(void *gx);
unsigned short *get_gxdma_buffer(void *gx);
int read_gxdma(void *gx);

void init_memory();
int init_parameter();
void calc_parameter();
void init();
void *thread_matrix_rotate(int *i);
void *thread_matrix_average(int *i);
void *thread_matrix_rotate_pi(int *i);
void *thread_matrix_average_pi(int *i);
void send_global(unsigned short sport, char *buf, int blen);
void send_mic(unsigned short mic);
void send_log(char *fmt, ...);
void send_param_logs();
void *thread_recv_udp(void *p);
void *thread_recv_pcie(void *p);
void parse_cmd(int sockfd, int *cmds, int sl, struct sockaddr_in their_addr);
void screening();
double difft(struct timeval start, struct timeval end);
void calcu_sin_cos();

static float *f_in = 0;
static float *f_sum = 0;
static float *f_avg = 0;

static unsigned short *s_in = 0;
static int *i_sum = 0;
static unsigned short *s_avg = 0;
static short *buffer = 0;
static int *volume = 0;
static int *volumeall = 0;
static int *volumemax = 0;
static int *deltall = 0;

static int *energy = 0;
static int *out_alarm = 0;
static int *otdry = 0;
static int *power = 0;
static int *g_ca = 0;
static int *g_ca2 = 0;
static int *g_at = 0;
static int delt;
static int delt1;
static short *out = 0;
static int nodes;
static int mics;
static int channel;
static int channel1;
static int channel2;
static int g_volumeall_flag = 0;
static int pulse_width = 200;
static int average_number = 3;
static int sample_rate = 2000;
static char logip[32];
static unsigned short logport;
static char globalip[32];
static unsigned short globalport;
static MICARRAY ma = {0};
static pthread_mutex_t pmmic;
static pthread_mutex_t pmlog;
static pthread_mutex_t pmbuf = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int pmbuf_flag = 0;
static int pi_flag = 0;
static int thread_num = 4;
static int debug = 0;
static int stop_flag = 0;
static int threshold_sn = 700;
static int flag_8001 = 0;
static float sintable[4000];
static float costable[4000];
static int freq = 400;
static short energy_flag = 1;
static short delt100_flag = 0;
static short delt_flag = 1;
static int b_col;
static int e_col;

static STARTENDCA sec_domain[1000]; //暂定用户分段总数>不可超过1000段
/*//仅当case6用户设置ca2时，这些变量才有用。
static int break_point[2000];//段端点，按序排列，当新的段过来，只要段不包含任何原有的端点，则是新段，否则替换原段
static int break_point_pre[2000];//段端点，按序排列，当新的段过来，只要段不包含任何原有的端点，则是新段，否则替换原段
static int break_point_num = 0;
static int break_point_pre_num = 0;*/
static int domain_num = 0;

static unsigned int tow_power[] = {1, 2, 4, 8, 16};

static void *gxdma;
static int g_card_sample_rate;
static int g_bsize;
static unsigned int g_version;

void my_func(int sign_no)
{
    if (sign_no == SIGTERM) {
        stop_flag = 1;
    }
    
    return;
}

int main(int argc, char **argv)
{
    int i;
    int p[256] = {0};
    pthread_t tip[256] = {0};
    struct timeval start;
    struct timeval end;
    short *buffer0;
    char tmpbuf[8192];
    struct sigaction action;
    short first_recv_pcie = 1;

    if (fork()) {
        exit(-1);
    }
    setpgrp();

    pthread_mutex_init(&pmmic, 0);
    pthread_mutex_init(&pmlog, 0);

    read_register(0x00030100, &g_version);
    g_card_sample_rate = 100000000*((g_version>>8)&0xF);//板卡采样率
    init_parameter();

    gxdma = init_gxdma(g_bsize);
    if (!gxdma) {
        send_log("gxdma init error\n");
        exit(-1);
    }

    init();

    init_memory();

    action.sa_handler = my_func;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGTERM, &action, 0);

    send_log("Start collecting ...");
    send_param_logs();
    calcu_sin_cos();//init sin and cos table
    pthread_create(&tip[0], 0, (void *(*)(void *))thread_recv_udp, 0);
    pthread_create(&tip[0], 0, (void *(*)(void *))thread_recv_pcie, 0);

    while (1) {
        gettimeofday(&start, 0);
        
        pthread_mutex_lock(&pmbuf);
        if (0 == pmbuf_flag) {
            pthread_cond_wait(&cond, &pmbuf);
        }

        for (i = 0; i < thread_num; ++i) {
            p[i] = i;
            if (1 == pi_flag) {
                pthread_create(&tip[i], 0, (void *(*)(void *))thread_matrix_rotate_pi, p + i);
            } else {
                pthread_create(&tip[i], 0, (void *(*)(void *))thread_matrix_rotate, p + i);
            }
        }
        //flag_8001++;
        //if (1 == flag_8001) {
            send_global(8001, (char *)buffer, 2*4*mics);
        //    flag_8001 = 0;
        //}
        for (i = 0; i < thread_num; ++i) {
            pthread_join(tip[i], 0);
        }
        
        if (debug) {
            buffer0 = buffer + 2;
            sprintf(tmpbuf, "%d %d %d %d %d %d %d %d %d", pmbuf_flag, 
                buffer0[0], buffer0[4], buffer0[8], buffer0[12],
                buffer0[204], buffer0[208], buffer0[212], buffer0[216]);
        }
       
 
        pmbuf_flag--;
        pthread_mutex_unlock(&pmbuf);

        if(1 == first_recv_pcie){// if first time recv from pcie,then memcpy 's_avg' before caculate average
            memcpy(s_avg, s_in, 2*mics*nodes);
            for(int j = 0; j < mics; j++){
                for(int in_j = nodes - AVGNUM; in_j < nodes; in_j++){
                    i_sum[j] += s_avg[j*nodes + in_j];
                }
            }
            first_recv_pcie = 0;
        }

        for (i = 0; i < thread_num; ++i) {
            p[i] = i;
            if (1 == pi_flag) {
                pthread_create(&tip[i], 0, (void *(*)(void *))thread_matrix_average_pi, p + i);
            } else {
                pthread_create(&tip[i], 0, (void *(*)(void *))thread_matrix_average, p + i);
            }
        }
        for (i = 0; i < thread_num; ++i) {
            pthread_join(tip[i], 0);
        }

        screening();

        if (1 == pi_flag) {
            memcpy(f_avg, f_in, 4*mics*nodes);
        } else {
            memcpy(s_avg, s_in, 2*mics*nodes);
        }

        gettimeofday(&end, 0);
        
        if (debug) {
            send_log("%.8f %s", difft(start, end), tmpbuf);
        }

        if (stop_flag) {
            pthread_mutex_lock(&pmbuf);
            break;
        }
    }

    free(buffer);
    free(f_in);
    free(f_sum);
    free(f_avg);
    free(s_in);
    free(i_sum);
    free(s_avg);
    free(out);
    free(volume);
    free(volumeall);
    free(volumemax);
    free(deltall);
    free(out_alarm);
    free(otdry);
    free(energy);
    free(power);
    free(g_ca);
    free(g_ca2);
    free(g_at);
    free(ma.mic_flag);
    free(ma.mic_ip);
    free(ma.mic_port);

    free_gxdma(gxdma);

    pthread_mutex_destroy(&pmmic);
    pthread_mutex_destroy(&pmlog);

    send_log("Stop collecting ...");

    return 0;
}

void *thread_recv_pcie(void *p)
{
    int i;
    short *buffer0;

    while (1) {
        read_gxdma(gxdma);
        buffer0 = get_gxdma_buffer(gxdma);
        if (-21846 != buffer0[0]) {
            send_log("read_gxdma position 0xaaaa");
            exit(-1);
        }
        memcpy(buffer, buffer0, g_bsize);
        pmbuf_flag++;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&pmbuf);
    }

    return 0;
}

double difft(struct timeval start, struct timeval end)
{
	return ((double)((end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec)/(double)1000000);
}

int init_parameter()
{
    enum json_tokener_error jerr;
    json_object *jso, *j;
    FILE *fp;
    char buf[8192] = {0};

    fp = fopen(CONFIG_FILE, "r");
    fread(buf, 1, 8192, fp);
    fclose(fp);

    jso = json_tokener_parse_verbose(buf, &jerr);
    if (jerr != json_tokener_success) {
        return -1;
    }

    j = json_object_object_get(jso, "pulse_width");
    if (0 == j) {
        return -3;
    }
    pulse_width = json_object_get_int(j);

    j = json_object_object_get(jso, "average_number");
    if (0 == j) {
        return -4;
    }
    average_number = json_object_get_int(j);

    j = json_object_object_get(jso, "sample_rate");
    if (0 == j) {
        return -5;
    }
    sample_rate = json_object_get_int(j);

    j = json_object_object_get(jso, "channel");
    if (0 == j) {
        return -6;
    }
    channel = json_object_get_int(j);
    channel1 = channel/10 - 1;
    // channel2 = channel%10 - 1;
    for(short i = 0; i < 4; ++i){
        if(channel >> (3-i)){
            channel2 = i;
            break;
        }
    }

    j = json_object_object_get(jso, "log_ip");
    if (0 == j) {
        return -7;
    }
    strcpy(logip, json_object_get_string(j));

    j = json_object_object_get(jso, "log_port");
    if (0 == j) {
        return -8;
    }
    logport = json_object_get_int(j);


    j = json_object_object_get(jso, "global_ip");
    if (0 == j) {
        return -9;
    }
    strcpy(globalip, json_object_get_string(j));

    j = json_object_object_get(jso, "global_port");
    if (0 == j) {
        return -10;
    }
    globalport = json_object_get_int(j);

    j = json_object_object_get(jso, "pi_flag");
    if (0 == j) {
        return -11;
    }
    pi_flag = json_object_get_int(j);

    j = json_object_object_get(jso, "thread_num");
    if (0 == j) {
        return -12;
    }
    thread_num = json_object_get_int(j);

    j = json_object_object_get(jso, "debug");
    if (0 == j) {
        return -13;
    }
    debug = json_object_get_int(j);
    
    json_object_put(jso);

    calc_parameter();

    return 1;
}

void calc_parameter()
{
    g_bsize = g_card_sample_rate*CHANNEL_NUM*2/10/tow_power[average_number];
    mics = g_card_sample_rate/sample_rate/tow_power[average_number];
    nodes = sample_rate/10;

    delt1 = nodes*3/100;
    //delt = nodes*50/100;
    delt = nodes*2/100;

    return;
}

void *thread_matrix_rotate(int *i)
{
    int r, c;
    short *s;
    int step = nodes/thread_num;
    int index = *i;
    unsigned short s1, s2;
    int start;
    int end;

    start = index*step;
    end = start + step;

    if (thread_num == index + 1) {
        end = nodes;
    }

    for (r = start; r < end; ++r) {
        s = buffer + 4*r*mics;
        for (c = 0; c < mics; ++c) {
            // s1 = s[4*c + channel1] + 32768;
            // s2 = s[4*c + channel2] + 32768;
            // s_in[c*nodes + r] = sqrt(s1*s1 + s2*s2);
            s2 = s[4*c + channel2] + BASE;//基底变为1000附近;
            if (-1 == channel1) {
                s_in[c*nodes + r] = s2;
            } else {
                s1 = s[4*c + channel1] + BASE;//基底变为1000附近;
                s_in[c*nodes + r] = sqrt(s1*s1 + s2*s2);
            }
        }
    }

    return 0;
}

void *thread_matrix_rotate_pi(int *i)
{
    int r, c;
    short *s;
    int step = nodes/thread_num;
    int index = *i;
    short s1, s2;
    int start;
    int end;

    start = index*step;
    end = start + step;

    if (thread_num == index + 1) {
        end = nodes;
    }

    for (r = start; r < end; ++r) {
        s = buffer + 4*r*mics;
        for (c = 0; c < mics; ++c) {
            s1 = abs(s[4*c + channel1]);
            s2 = abs(s[4*c + channel2]);
            if (0 == s2) {
                s2 = 1;
            }
            f_in[c*nodes + r] = atan((float)s1/(float)(s2));
        }
    }

    return 0;
}

void *thread_matrix_average(int *i)
{
    int r, c;
    unsigned short *s_in0, *s_avg0;
    short *out0;
    int step = mics/thread_num;
    int index = *i;
    float real = 0;
    float imag = 0;
    int start;
    int end;
    int min, max, min1, max1, minall, maxall, n, n1, s_z;

    start = index*step;
    end = start + step;

    if (thread_num == index + 1) {
        end = mics;
    }

    for (r = start; r < end; ++r) {
        out0 = out + r*nodes;
        s_in0 = s_in + r*nodes;
        s_avg0 = s_avg + r*nodes;
        volume[r] = 0;
        volumeall[r] = 0;
        volumemax[r] = 0;
        deltall[3*r] = 0;
        deltall[3*r+1] = 0;
        deltall[3*r+2] = 0;
        minall = 65536;
        maxall = -65535;
        n =  0;
        n1 =  0;
        real = 0;
        imag = 0;
        for (c = 0; c < nodes; ++c) {
            s_z = i_sum[r]/AVGNUM;
            out0[c] = s_z==0 ? 0 : ((float)s_in0[c]/s_z - 1) * 5000;
            real += out0[c] * costable[c];
            imag += out0[c] * sintable[c];
            if(c - AVGNUM < 0){//本次数据刚开始，取上次的数据
                i_sum[r] += s_in0[c] - s_avg0[nodes - AVGNUM + c];
            }else{
                i_sum[r] += s_in0[c] - s_in0[c - AVGNUM];
            }

            if(0 == n){
                min = 65536;
                max = -65535;
            }
        
            if(0 == n1){
                min1 = 65536;
                max1 = -65535;
            }
         
            if(max1 < out0[c]){
                max1 = out0[c];
            }
            if(min1 > out0[c]){
                min1 = out0[c];
            }

            if (max < out0[c]) {
                max = out0[c];
            }
            if (maxall < out0[c]) {
                maxall = out0[c];
            }
            if (min > out0[c]) {
                min = out0[c];
            }
            if (minall > out0[c]) {
                minall = out0[c];
            }
            n++;
            n1++;
           
            if (delt == n) {
                if (volume[r] < max - min) {
                    volume[r] = max - min;
                }
                deltall[3*r + 1] = volume[r];
                n = 0;
            }
            
            if(delt1 == n1){
                if(deltall[3*r] < max1 - min1){
                    deltall[3*r] = max1 - min1;
                }
                n1 = 0;
            }
        }
        energy[r] = abs(real)+abs(imag);
        volumeall[r] = maxall - minall + 1;
        deltall[3*r + 2] = volumeall[r];
        volumemax[r] = maxall;
        if (n > 0) {
            if (volume[r] < max - min) {
                volume[r] = max - min;
            }
            deltall[3*r + 1] = volume[r];
        }

        if (n1 > 0) {
            if (deltall[3*r] < max1 - min1) {
                deltall[3*r] = max1 - min1;
            }
        }
        send_mic(r);
    }

    return 0;
}

void *thread_matrix_average_pi(int *i)
{
    int r, c;
    float *f_in0, *f_avg0;
    short *out0;
    float f_z;
    int step = mics/thread_num;
    int index = *i;
    float cc = 1;
    int start;
    int end;

    start = index*step;
    end = start + step;

    if (thread_num == index + 1) {
        end = mics;
    }

    for (r = start; r < end; ++r) {
        out0 = out + r*nodes;
        f_in0 = f_in + r*nodes;
        f_avg0 = f_avg + r*nodes;
        volume[r] = 0;
        for (c = 0; c < nodes; ++c) {
            f_z = f_sum[r]/nodes;
            //cc = 5*cos(2*f_z);
            //cc = atan(4*(3.14/4 - 2*f_z))*4;
            //cc = tan(3.14/4 - 2*f_z) + 1;
            out0[c] = (f_in0[c] - f_z)*4000;
            f_sum[r] += f_in0[c] - f_avg0[c];
            volume[r] += abs(out0[c]);
        }

        send_mic(r);
    }

    return 0;
}

void screening()
{
    int i;
    int j;
    int step = VOLUME_LEN/tow_power[average_number];
    int except_step = EXCEPT_LEN/tow_power[average_number];
    int begin_col = BEGIN_LEN/tow_power[average_number];
    int except_start;
    int except_end;
    long total;
    long total0;
    int len = 0;
    long l_ca[mics];
    long l_ca_o[mics];

    for(i = 0; i < domain_num; i++){
        total = 0;
        int s = sec_domain[i].start;
        int e = sec_domain[i].end;
        int ca2 = sec_domain[i].ca2;
        int l_ca_max_num = (e-s+1)*ca2/100;
        int at = 0;
        if(l_ca_max_num == 0){//屏蔽路段
            for(j = s; j <= e; j++){
                g_at[j] = 0;
                power[j] = 0;
                otdry[j] = 0;
            }
            continue;
        }
        for(j = s; j <= e; j++){
            total += volume[j];
        }

        for(j = s; j <= e; j++){
            except_start = j - except_step/2 < s ? s : j - except_step/2;
            except_end = j + except_step/2 > e ? e : j + except_step/2;
            int exce_num = 0;
            total0 = total;
            for(int exce = except_start; exce <= except_end; exce++){
                total0 -= volume[exce];
                exce_num++;
            }
            total0 = total0/(e-s+1-exce_num) == 0 ? 1 : total0/(e-s+1-exce_num);
            otdry[j] = total0;
            //l_ca_o[j] = l_ca[j] = (volume[j]*10/total0)*(((long)volume[j]*1000)/volumeall[j]);
            l_ca_o[j] = l_ca[j] = volume[j]*10/total0;
        }

        for(int cu_num = s; cu_num < (s+l_ca_max_num); cu_num++){
            int l_ca_temp;
            for(j = cu_num; j <= e; j++){
                if(l_ca[j] > l_ca[cu_num]){
                   l_ca_temp = l_ca[cu_num];
                   l_ca[cu_num] = l_ca[j];
                   l_ca[j] = l_ca_temp;
                }
            }
            if(cu_num -  s >= l_ca_max_num*EXCEPT_MAX_RATIO/100) at += l_ca[cu_num];
        }

        at /= (l_ca_max_num-l_ca_max_num*EXCEPT_MAX_RATIO/100);
        if(at ==0) at++;

        for(j = s; j <= e; j++){
            g_at[j] = at;
            int l_ca1 = l_ca_o[j]*10/at;
            power[j] = l_ca1;
            if (l_ca1 > g_ca[j]) {
                if(j <= begin_col) continue;//小于80m的报警不报
                //fprintf(stderr,"dis is %d, p is %d, total is %d, ca is %d\n", j*8, p, total0, g_ca[j]);
                out_alarm[len++] = j;
                out_alarm[len++] = l_ca1;
            }
        }
    }

    //send_global(8003, (char *)otdry, mics*4);
    //send_global(8005, (char *)power, mics*4);
    if(0 == energy_flag){
        send_global(8009, (char *)energy, mics*4);
    }
    if (len > 0) {
        send_global(8002, (char *)out_alarm, len*4);
    }
    if(g_volumeall_flag == 0){
        delt100_flag++;
        if(delt100_flag == 5){
            send_global(8008, (char *)volumeall, mics*4);//瀑布图源数据
            delt100_flag = 0;
        }
    }

    if(0 == delt_flag){
        send_global(8010, (char *)(deltall + 3*b_col), 3*(e_col - b_col + 1)*4);
    }

    return;
}


void init_memory()
{
    int i;

    if (buffer) {
        free(buffer);
        buffer = 0;
    }
    buffer = (short *)malloc(g_bsize);

    if (f_in) {
        free(f_in);
        f_in = 0;
    }
    f_in = (float *)malloc(4*nodes*mics);

    if (f_avg) {
        free(f_avg);
        f_avg = 0;
    }
    f_avg = (float *)malloc(4*nodes*mics);
    memset(f_avg, 0, 4*nodes*mics);

    if (f_sum) {
        free(f_sum);
        f_sum = 0;
    }
    f_sum = (float *)malloc(4*mics);
    memset(f_sum, 0, 4*mics);

    if (s_in) {
        free(s_in);
        s_in = 0;
    }
    s_in = (unsigned short *)malloc(2*nodes*mics);

    if (s_avg) {
        free(s_avg);
        s_avg = 0;
    }
    s_avg = (unsigned short *)malloc(2*nodes*mics);
    memset(s_avg, 0, 2*nodes*mics);

    if (out) {
        free(out);
        out = 0;
    }
    out = (short *)malloc(2*nodes*mics);

    if (i_sum) {
        free(i_sum);
        i_sum = 0;
    }
    i_sum = (int *)malloc(4*mics);
    memset(i_sum, 0, 4*mics);

    if (volume) {
        free(volume);
        volume = 0;
    }
    volume = (int *)malloc(4*mics);
    memset(volume, 0, 4*mics);

    if (volumeall) {
        free(volumeall);
        volumeall = 0;
    }
    volumeall = (int *)malloc(4*mics);
    memset(volumeall, 0, 4*mics);

    if (volumemax) {
        free(volumemax);
        volumemax = 0;
    }
    volumemax = (int *)malloc(4*mics);
    memset(volumemax, 0, 4*mics);

    if(deltall){
        free(deltall);
        deltall = 0;
    }
    deltall = (int *)malloc(4*mics*3);//save delt3,delt50,delt100
    memset(deltall, 0, 4*mics*3);

    if (g_at) {
        free(g_at);
        g_at = 0;
    }
    g_at = (int *)malloc(4*mics);

    //init se_domain
    int volume_num = VOLUME_LEN/tow_power[average_number]; //800m换算co
    domain_num = ceil((float)mics/volume_num);
    for(int d = 0; d < domain_num; d++){
        sec_domain[d].start = d*volume_num;
        sec_domain[d].ca2 = 20;
        if(d != domain_num - 1){
            sec_domain[d].end = d*volume_num + volume_num -1;
        }else{
            sec_domain[d].end = mics - 1;
        }
    }

    if (out_alarm) {
        free(out_alarm);
        out_alarm = 0;
    }
    out_alarm = (int *)malloc(4*2*mics);
    
    if (otdry) {
        free(otdry);
        otdry = 0;
    }
    otdry = (int *)malloc(4*mics);

    if(energy){
        free(energy);
        energy = 0;
    }
    energy = (int *)malloc(4*mics);

    if (power) {
        free(power);
        power = 0;
    }
    power = (int *)malloc(4*mics);


    if (g_ca) {
        free(g_ca);
        g_ca = 0;
    }
    g_ca = (int *)malloc(4*mics);
    for (i = 0; i < mics; ++i) {
        g_ca[i] = 30;
    }

    if (g_ca2) {
        free(g_ca2);
        g_ca2 = 0;
    }
    g_ca2 = (int *)malloc(4*mics);
    for (i = 0; i < mics; ++i) {
        g_ca2[i] = 20;
    }

    if (ma.mic_ip) {
        free(ma.mic_ip);
        ma.mic_ip = 0;
    }
    ma.mic_ip = (unsigned int *)malloc(4*mics);
    memset(ma.mic_ip, 0, 4*mics);

    if (ma.mic_port) {
        free(ma.mic_port);
        ma.mic_port = 0;
    }
    ma.mic_port = (unsigned short *)malloc(2*mics);
    memset(ma.mic_port, 0, 2*mics);

    if (ma.mic_flag) {
        free(ma.mic_flag);
        ma.mic_flag = 0;
    }
    ma.mic_flag = (char *)malloc(mics);
    memset(ma.mic_flag, 0, mics);
    
    return;
}

void init()
{
    //先开启APD保护脉宽
    write_register(0x00030003, 0);
    write_register(0x00030001, 1);
    usleep(100000);
    write_register(0x00030001, 0);
    write_register(0x00030004, 0x40000000);
    sleep(2);
    write_register(0x00030010, 30/(NANO_SECONDS/g_card_sample_rate));
    write_register(0x00030011, average_number);
    write_register(0x00030012, g_card_sample_rate/sample_rate - 1);
    write_register(0x00030003, 1);

    sleep(4);

    //正常脉宽
    write_register(0x00030003, 0);
    write_register(0x00030001, 1);
    usleep(100000);
    write_register(0x00030001, 0);
    write_register(0x00030004, 0x40000000);
    sleep(2);
    write_register(0x00030010, pulse_width/(NANO_SECONDS/g_card_sample_rate));
    write_register(0x00030011, average_number);
    write_register(0x00030012, g_card_sample_rate/sample_rate - 1);
    write_register(0x00030003, 1);
}

void send_mic(unsigned short mic)
{
    int sockfd;
	struct sockaddr_in their_addr;
    struct sockaddr_in my_addr;

    pthread_mutex_lock(&pmmic);
    if (!ma.mic_flag[mic]) {
        pthread_mutex_unlock(&pmmic);
        return;
    }
    memset(&their_addr, 0, sizeof(their_addr));
    their_addr.sin_family = PF_INET;
    their_addr.sin_port = htons(ma.mic_port[mic]);
    their_addr.sin_addr.s_addr = ma.mic_ip[mic];
    pthread_mutex_unlock(&pmmic);

    sockfd=socket(PF_INET, SOCK_DGRAM, 0);
    
    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(10000 + mic);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

    sendto(sockfd, out + mic*nodes, 2*nodes, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));

    close(sockfd);

    return;
}

void send_global(unsigned short sport, char *buf, int blen)
{
    int sockfd;
	struct sockaddr_in their_addr;
    struct sockaddr_in my_addr;
    int len;

	sockfd=socket(PF_INET, SOCK_DGRAM, 0);
    
    pthread_mutex_lock(&pmlog);
	memset(&their_addr, 0, sizeof(their_addr));
	their_addr.sin_family = PF_INET;
	their_addr.sin_port = htons(globalport);
	their_addr.sin_addr.s_addr = inet_addr(globalip);
    pthread_mutex_unlock(&pmlog);

    memset(&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = PF_INET;
	my_addr.sin_port = htons(sport);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

    while (blen > 0) {
        if (blen > 60007) {
            len = sendto(sockfd, buf, 60007, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
        } else {
            len = sendto(sockfd, buf, blen, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
        }
        //if(sport == 8002) send_log("send len is %d\n", len);
        if (len < 0) {
            send_log("send global %d %s", len, strerror(errno));
            break;
        } else {
            blen -= len;
            buf += len;
        }
    }

    close(sockfd);

    return;
}

void *thread_recv_udp(void *p)
{
    int sockfd;
    int sl;
    struct sockaddr_in my_addr;
    struct sockaddr_in their_addr;
    char buf[4096];
    int len;
    int optval = 1;
    
    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(RECV_PORT);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    setsockopt(sockfd , SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof(optval));
    
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0) {
        send_log("Bind Error: %s", strerror(errno));
        exit(-1);
    }

    while (1) {
        len = sizeof(their_addr);
        sl = recvfrom(sockfd, buf, 4096, 0, (struct sockaddr *)&their_addr, &len);
        parse_cmd(sockfd, (int *)buf, sl, their_addr);
    }

    close(sockfd);
    
    return 0;
}

void parse_cmd(int sockfd, int *cmds, int sl, struct sockaddr_in their_addr)
{
    int i;
    int len;
    unsigned int buf[4096];
    struct in_addr addr;
    int *p;

    switch (cmds[0]) {
        // logip logport globalip globalport
        case 0:
            pthread_mutex_lock(&pmlog);
            addr.s_addr = cmds[1];
            strcpy(logip, inet_ntoa(addr));
            logport = cmds[2];
            addr.s_addr = cmds[3];
            strcpy(globalip, inet_ntoa(addr));
            globalport = cmds[4];
            pthread_mutex_unlock(&pmlog);
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        // pulse_width sample_rate average_number channel
        case 1:
            len = 0;
            buf[len++] = cmds[0];
            buf[len++] = pulse_width;
            buf[len++] = sample_rate;
            buf[len++] = average_number;
            buf[len++] = channel;
            sendto(sockfd, buf, 4*len, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        // mic ip port a/n
        case 2:
            pthread_mutex_lock(&pmmic);
            ma.mic_flag[cmds[1]] = cmds[4];
            ma.mic_ip[cmds[1]] = cmds[2];
            ma.mic_port[cmds[1]] = cmds[3];
            pthread_mutex_unlock(&pmmic);
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        //
        case 3:
            len = 0;
            buf[len++] = cmds[0];
            for (i = 0; i < mics; ++i) {
                if (ma.mic_flag[i]) {
                    buf[len++] = i;
                    buf[len++] = ma.mic_ip[i];
                    buf[len++] = ma.mic_port[i];
                    if (len > 1000) {
                        break;
                    }
                }
            }
            sendto(sockfd, buf, 4*len, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        // mic ca
        case 4:
            p = cmds + 1;
            for (i = 0; i < sl/4 - 1; i += 2) {
                g_ca[p[i]] = p[i + 1];
            }
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        // set threshold_sn
        case 5:
            threshold_sn = cmds[1];
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;

        //get version
        case 7:
            buf[0] = cmds[0];
            buf[1] = VERSION;
            sendto(sockfd, buf, 8, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        case 8:
            p = cmds + 1;
            switch (p[1]){
                case 0:
                    g_volumeall_flag = p[2];
                case 8:
                    g_volumeall_flag = p[2];
            }
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        // get all ca
        case 10:
            {
                unsigned int *ca0;
                int blen = 4*(mics + 1);
                char *buf_ca0;

                ca0 = malloc(blen);
                buf_ca0 = (char *)ca0;
                ca0[0] = 10;
                memcpy(ca0 + 1, g_ca, 4*mics);
                while (blen > 0) {
                    if (blen > 60007) {
                        len = sendto(sockfd, buf_ca0, 60007, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
                    } else {
                        len = sendto(sockfd, buf_ca0, blen, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
                    }
                    if (len < 0) {
                        send_log("send global %d %s", len, strerror(errno));
                        break;
                    } else {
                        blen -= len;
                        buf_ca0 += len;
                    }
                }
                free(ca0);
            }
            break;
        //set freq
        case 11:
            energy_flag = cmds[1];
            freq = cmds[2];
            calcu_sin_cos();
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
        case 12:
            delt_flag = cmds[2];
            b_col = cmds[3];
            e_col = cmds[4];
            sendto(sockfd, cmds, 4, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            if(e_col < b_col){
                send_log("balck send error! recv b_col is %d, e_col is %d\n", b_col, e_col);
                b_col = e_col = 0;
            }
            break;
        default:
            buf[0] = cmds[0];
            len = sprintf((char *)buf + 4, "unknown cmd") + 4;
            sendto(sockfd, buf, len, 0, (struct sockaddr *)&their_addr, sizeof(their_addr));
            break;
    }

    return;
}

void send_log(char *fmt, ...)
{
    va_list ap;
    char buf[1024] = {0};
    int sockfd;
	struct sockaddr_in their_addr;
    struct sockaddr_in my_addr;
    unsigned short sport = LOG_SOURCE_PORT;
    
    va_start(ap, fmt);
    vsprintf(buf, fmt, ap);
    va_end(ap);

	sockfd=socket(PF_INET, SOCK_DGRAM, 0);
    
    pthread_mutex_lock(&pmlog);
	memset(&their_addr, 0, sizeof(their_addr));
	their_addr.sin_family = PF_INET;
	their_addr.sin_port = htons(logport);
	their_addr.sin_addr.s_addr = inet_addr(logip);
    pthread_mutex_unlock(&pmlog);

    memset(&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = PF_INET;
	my_addr.sin_port = htons(sport);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

    sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&their_addr, sizeof(their_addr));

    close(sockfd);

    return;
}

void send_param_logs()
{
    send_log("Version: 0x%08x\n", g_version);
    send_log("Card Sample Rate: %u\n", g_card_sample_rate);
    send_log("Average Number: %u", average_number);
    send_log("Sample Rate: %u", sample_rate);
    send_log("Mic Number: %u", mics);
    send_log("Node Number: %u", nodes);
    send_log("Channel Index: %u", channel);
    send_log("Pulse Width: %u", pulse_width);
    send_log("Thread Number: %u", thread_num);
    send_log("Debug: %u", debug);
    send_log("PI Flag: %u", pi_flag);
    send_log("Global IP: %s", globalip);
    send_log("Global Port: %u", globalport);
    send_log("Log IP: %s", logip);
    send_log("Log Port: %u", logport);

    return;
}

void calcu_sin_cos()
{
    float t;
    for(int i = 0; i < nodes; i++){
        t = (float)i/sample_rate;//计算当前数所在的时间
        sintable[i] = sin(2*PI*freq*t);//sin(wt),w=2PIf
        costable[i] = cos(2*PI*freq*t);//cos(wt)
    }
}
